A function is called reentrant if it can be interrupted in the middle of its execution and then safely called again ("re-entered") before its
previous invocations complete execution.
It is especially important that multi-threaded applications do not call the same non-reentrant function from different threads.
This rule will trigger an issue each time a function in the configurable list is invoked.
A call will be matched differently depending on the presence of the scope resolution operator ::
in the function name from the
configurable list.
For example, namespace a { namespace b { void f(); } }
can be matched with "f", "b::f", "a::b::f", "::a::b::f" (fully qualified name
yielding most precise results).
It is recommended to provide fully qualified names to the configurable list (i.e., start each name with ::
), even for the functions in
the global namespace.
Noncompliant code example
Given a function that includes localtime
:
#include <stdio.h>
#include <time.h>
void print_date_and_time(struct tm *time_ptr)
{
printf(
"Current date and time: %d/%02d/%02d %02d:%02d:%02d\n",
time_ptr->tm_year + 1900,
time_ptr->tm_mon,
time_ptr->tm_mday,
time_ptr->tm_hour,
time_ptr->tm_min,
time_ptr->tm_sec);
}
void print_unix_epoch_date_and_time()
{
time_t unix_epoch_time = (time_t)0;
struct tm *local_time_ptr = localtime(&unix_epoch_time); // Noncompliant, call to the non-reentrant localtime() function
print_date_and_time(local_time_ptr);
}
int main(int argc, char* argv[])
{
time_t current_time;
struct tm *local_time_ptr;
time(¤t_time);
local_time_ptr = localtime(¤t_time); // Noncompliant, call to the non-reentrant localtime() function
// As expected, this will print: Current date and time: 1970/00/01 01:00:00
print_unix_epoch_date_and_time();
// This will actually also print Current date and time: 1970/00/01 01:00:00
// Indeed, localtime() is non-reentrant, and always returns the same pointer
print_date_and_time(local_time_ptr);
return 0;
}
Compliant solution
#include <stdio.h>
#include <time.h>
void print_date_and_time(struct tm *time_ptr)
{
printf(
"Current date and time: %d/%02d/%02d %02d:%02d:%02d\n",
time_ptr->tm_year + 1900,
time_ptr->tm_mon,
time_ptr->tm_mday,
time_ptr->tm_hour,
time_ptr->tm_min,
time_ptr->tm_sec);
}
void print_unix_epoch_date_and_time()
{
time_t unix_epoch_time = (time_t)0;
struct tm local_time;
localtime_r(&unix_epoch_time, &local_time); // Compliant
print_date_and_time(&local_time);
}
int main(int argc, char* argv[])
{
time_t current_time;
struct tm local_time;
time(¤t_time);
localtime_r(¤t_time, &local_time); // Compliant
// As expected, this will print: Current date and time: 1970/00/01 01:00:00
print_unix_epoch_date_and_time();
// As expected, this will print the current date and time
print_date_and_time(&local_time);
return 0;
}